/******************************************************************************
  A simple program of Hisilicon HI3531 video encode implementation.
  Copyright (C), 2010-2011, Hisilicon Tech. Co., Ltd.
 ******************************************************************************
    Modification:  2011-2 Created
******************************************************************************/
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* End of #ifdef __cplusplus */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <../../include/mp4v2/mp4v2.h> 
#include "ringfifo.h"

#include "sample_comm.h"
#include "loadbmp.h"
#include "app_key.h"
#include "faac.h"
#include "faaccfg.h"
#include "recordfile_common.h"

faacEncHandle encoder;
faacEncConfigurationPtr config;

VIDEO_NORM_E gs_enNorm = VIDEO_ENCODING_MODE_NTSC;

#ifdef hi3518ev201

HI_U32 g_u32BlkCnt = 4;
#endif

#ifdef hi3518ev200

HI_U32 g_u32BlkCnt = 4;

#endif

#ifdef hi3516cv200

HI_U32 g_u32BlkCnt = 10;

#endif




static PAYLOAD_TYPE_E gs_enPayloadType = PT_LPCM;

//static HI_BOOL gs_bMicIn = HI_FALSE;

static HI_BOOL gs_bAioReSample  = HI_FALSE;
static HI_BOOL gs_bUserGetMode  = HI_FALSE;
static HI_BOOL gs_bAoVolumeCtrl = HI_TRUE;
static AUDIO_SAMPLE_RATE_E enInSampleRate  = AUDIO_SAMPLE_RATE_BUTT;
static AUDIO_SAMPLE_RATE_E enOutSampleRate = AUDIO_SAMPLE_RATE_BUTT;
static HI_U32 u32AencPtNumPerFrm = 0;
/* 0: close, 1: open*/
static HI_U32 u32AiVqeType = 1;  
/* 0: close, 1: open*/
static HI_U32 u32AoVqeType = 1;  


#define SAMPLE_DBG(s32Ret)\
do{\
    printf("s32Ret=%#x,fuc:%s,line:%d\n", s32Ret, __FUNCTION__, __LINE__);\
}while(0)


int Record_PCM2AAC(RecordStreamInfo_T * datainfo , char * data , int len , RecordStreamRemain_T * remain)
{
	int writelen = 0;

	datainfo->datalen= 0;
	
	if(remain->aacheadle == NULL)
	{
		//AudioEncodeParam_T audio;
		//API_GetParameter(PARAM_AUDIO, &audio);

		remain->bitsize =16; //audio.bitrate;
		// 鎵撳紑faac缂栫爜鍣ㄥ紩鎿? 
		/*sampleRate 鍏堝浐瀹?8k
		numChannels= 1
		*/
		remain->aacheadle = faacEncOpen(8000 , 1 , (long unsigned int *)&remain->nInputSamples, (long unsigned int *)&remain->nMaxOutputBytes);
	
		if(remain->aacheadle == NULL)  
		{  
			printf("open aac encoder error \n");
			return -1;  
		} 
		// 鑾峰彇褰撳墠缂栫爜鍣ㄤ俊鎭?
		faacEncConfigurationPtr pConfiguration; 
    		pConfiguration = faacEncGetCurrentConfiguration(remain->aacheadle);

		pConfiguration->inputFormat = FAAC_INPUT_16BIT;
		 // 0 = Raw; 1 = ADTS  
    		pConfiguration->outputFormat = 0;
		pConfiguration->aacObjectType = LOW;

		pConfiguration->mpegVersion = 0;


		faacEncSetConfiguration(remain->aacheadle, pConfiguration);


		unsigned char * buff = NULL;
		long unsigned int headlen = 0;

		faacEncGetDecoderSpecificInfo(remain->aacheadle , &buff , &headlen);

		memcpy(datainfo->aacspec , buff , headlen);
		datainfo->aacspeclen = headlen;
		//printf("\n==========aacspec:%d-[0x%x][0x%x] =============\n\n", (int)headlen , ( unsigned int)buff[0] , ( unsigned int)buff[1]);
	   //   printf("\n----------nInputSamples:%d  , nMaxOutputBytes:%d ---------\n\n" , remain->nInputSamples ,remain->nMaxOutputBytes);

		
	}
	writelen = (remain->pcmleftlen + len <= PCM_BUFF_MAX_LEN)?len: PCM_BUFF_MAX_LEN - remain->pcmleftlen;

	
	memcpy(remain->pcmbuf + remain->pcmleftlen , data , writelen);
	remain->pcmleftlen += writelen;


	writelen = remain->nInputSamples * (remain->bitsize >> 3);
	if(remain->pcmleftlen >= writelen)
	{
		datainfo->datalen = faacEncEncode(remain->aacheadle, (int*)remain->pcmbuf,  remain->nInputSamples , (unsigned char *)remain->aacbuf, remain->nMaxOutputBytes);
	//	datainfo->pdata = remain->aacbuf;
		memcpy(datainfo->pdata,remain->aacbuf,datainfo->datalen);
		memmove(remain->pcmbuf , remain->pcmbuf + writelen , remain->pcmleftlen - writelen);

		remain->pcmleftlen -= writelen;
	}
	return datainfo->datalen;
}

/******************************************************************************
* function : PT Number to String
******************************************************************************/
static char* SAMPLE_AUDIO_Pt2Str(PAYLOAD_TYPE_E enType)
{
    if (PT_G711A == enType)  
    {
        return "g711a";
    }
    else if (PT_G711U == enType)  
    {
        return "g711u";
    }
    else if (PT_ADPCMA == enType)  
    {
        return "adpcm";
    }
    else if (PT_G726 == enType) 
    {
        return "g726";
    }
    else if (PT_LPCM == enType)  
    {
        return "pcm";
    }
    else 
    {
        return "data";
    }
}

/******************************************************************************
* function : Open Aenc File
******************************************************************************/
static FILE * SAMPLE_AUDIO_OpenAencFile(AENC_CHN AeChn, PAYLOAD_TYPE_E enType)
{
    FILE* pfd;
    HI_CHAR aszFileName[FILE_NAME_LEN];

    /* create file for save stream*/
    snprintf(aszFileName, FILE_NAME_LEN, "audio_chn%d.%s", AeChn, SAMPLE_AUDIO_Pt2Str(enType));
    pfd = fopen(aszFileName, "w+");
    if (NULL == pfd)
    {
        printf("%s: open file %s failed\n", __FUNCTION__, aszFileName);
        return NULL;
    }
    printf("open stream file:\"%s\" for aenc ok\n", aszFileName);
    return pfd;
}

/******************************************************************************
* function : Open Adec File
******************************************************************************/
static FILE *SAMPLE_AUDIO_OpenAdecFile(ADEC_CHN AdChn, PAYLOAD_TYPE_E enType)
{
    FILE* pfd;
    HI_CHAR aszFileName[FILE_NAME_LEN];

    /* create file for save stream*/
    snprintf(aszFileName, FILE_NAME_LEN ,"audio_chn%d.%s", AdChn, SAMPLE_AUDIO_Pt2Str(enType));
    pfd = fopen(aszFileName, "rb");
    if (NULL == pfd)
    {
        printf("%s: open file %s failed\n", __FUNCTION__, aszFileName);
        return NULL;
    }
    printf("open stream file:\"%s\" for adec ok\n", aszFileName);
    return pfd;
}



HI_S32 exit_audio_process()
{
    
    HI_S32 i, s32Ret;
    AUDIO_DEV   AiDev = SAMPLE_AUDIO_AI_DEV;
    AI_CHN      AiChn;
    AUDIO_DEV   AoDev = SAMPLE_AUDIO_AO_DEV;
    AO_CHN      AoChn = 0;
    ADEC_CHN    AdChn = 0;
    HI_S32      s32AiChnCnt;
	HI_S32      s32AoChnCnt = 1;
    HI_S32      s32AencChnCnt = 1;
    AENC_CHN    AeChn;
    HI_BOOL     bSendAdec = HI_TRUE;
    FILE        *pfd = NULL;
    AIO_ATTR_S stAioAttr;
    /********************************************
    step 6: exit the process
    ********************************************/
    if (HI_TRUE == bSendAdec)
    {
        s32Ret = SAMPLE_COMM_AUDIO_DestoryTrdAencAdec(AdChn);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }
        
        s32Ret = SAMPLE_COMM_AUDIO_StopAo(AoDev, s32AoChnCnt, gs_bAioReSample, HI_FALSE);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }
        
        s32Ret = SAMPLE_COMM_AUDIO_StopAdec(AdChn);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }
        
        s32Ret = SAMPLE_COMM_AUDIO_AoUnbindAdec(AoDev, AoChn, AdChn);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }
        
    }
    
    for (i=0; i<s32AencChnCnt; i++)
    {
        AeChn = i;
        AiChn = i;

        if (HI_TRUE == gs_bUserGetMode)
        {
            s32Ret = SAMPLE_COMM_AUDIO_DestoryTrdAi(AiDev, AiChn);
            if (s32Ret != HI_SUCCESS)
            {
                SAMPLE_DBG(s32Ret);
                return HI_FAILURE;
            }
        }
        else
        {        
            s32Ret = SAMPLE_COMM_AUDIO_AencUnbindAi(AiDev, AiChn, AeChn);
            if (s32Ret != HI_SUCCESS)
            {
                SAMPLE_DBG(s32Ret);
                return HI_FAILURE;
            }
        }
    }
    
    s32Ret = SAMPLE_COMM_AUDIO_StopAenc(s32AencChnCnt);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }
    
    s32Ret = SAMPLE_COMM_AUDIO_StopAi(AiDev, 1, gs_bAioReSample, HI_FALSE);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}



/******************************************************************************
* function : show usage
******************************************************************************/
void SAMPLE_VENC_Usage(char *sPrgNm)
{
    printf("Usage : %s <index>\n", sPrgNm);
    printf("index:\n");
    printf("\t 0) 1*1080p H264 + 1*VGA H264.\n");
    printf("\t 1) 1*1080p MJPEG encode + 1*1080p jpeg.\n");
    printf("\t 2) low delay encode(only vi-vpss online).\n");
    printf("\t 3) roi background framerate.\n");
    printf("\t 4) Thumbnail of 1*1080p jpeg.\n");
#ifndef hi3518ev201
	printf("\t 5) svc-t H264\n");
#endif
    return;
}

/******************************************************************************
* function : to process abnormal case                                         
******************************************************************************/
void SAMPLE_VENC_HandleSig(HI_S32 signo)
{
    if (SIGINT == signo || SIGTERM == signo)
    {
        SAMPLE_COMM_AUDIO_DestoryAllTrd();
        SAMPLE_COMM_ISP_Stop();
        SAMPLE_COMM_SYS_Exit();
        printf("\033[0;31mprogram termination abnormally!\033[0;39m\n");
    }
    exit(-1);
}

void SAMPLE_AUDIO_HandleSig(HI_S32 signo)
{
    if (SIGINT == signo || SIGTERM == signo)
    {
        SAMPLE_COMM_AUDIO_DestoryAllTrd();
        SAMPLE_COMM_ISP_Stop();
        SAMPLE_COMM_SYS_Exit(); 
        printf("\033[0;31mprogram exit abnormally!\033[0;39m\n");
    }

    exit(0);
}


/******************************************************************************
* function : to process abnormal case - the case of stream venc
******************************************************************************/
void SAMPLE_VENC_StreamHandleSig(HI_S32 signo)
{

    if (SIGINT == signo || SIGTSTP == signo)
    {
        SAMPLE_COMM_ISP_Stop();
        SAMPLE_COMM_SYS_Exit();
        printf("\033[0;31mprogram exit abnormally!\033[0;39m\n");
    }

    exit(0);
}

#define VENC_RECORD_CHNID				0
#define VENC_RECORD_LOGO_OSD_HANDLE		2
#define VENC_RECORD_TIME_OSD_HANDLE		11

HI_VOID* SAMPLE_RGN_AddVideoTimestamp(HI_VOID* p)
{
	HI_S32 s32Ret = HI_SUCCESS;
	time_t timep;
	struct tm *pLocalTime;
	HI_U8 seconds = 80;

	RGN_HANDLE Handle;
	Handle = VENC_RECORD_TIME_OSD_HANDLE;

	while (1)
	{
		time(&timep);
		pLocalTime = localtime(&timep);
		if (seconds == pLocalTime->tm_sec){
			usleep(150*1000);
			continue;
		} else {
			seconds = pLocalTime->tm_sec;
		}

		s32Ret = SAMPLE_RGN_Add( Handle, VENC_RECORD_TIME_OSD_HANDLE);
		if (HI_SUCCESS != s32Ret)
		{
			printf("SAMPLE_RGN_Add line %d  failed! s32Ret: 0x%x.\n",__LINE__, s32Ret);
			break;
		}
	}

	pthread_detach(pthread_self());

	return 0;
}


HI_S32 SAMPLE_RGN_UpdateCanvas(const char *filename, BITMAP_S *pstBitmap, HI_BOOL bFil, 
    HI_U32 u16FilColor, SIZE_S *pstSize, HI_U32 u32Stride, PIXEL_FORMAT_E enPixelFmt)
{
    OSD_SURFACE_S Surface;
    OSD_BITMAPFILEHEADER bmpFileHeader;
    OSD_BITMAPINFO bmpInfo;

    if(GetBmpInfo(filename, &bmpFileHeader, &bmpInfo) < 0)
    {
		printf("GetBmpInfo err!\n");
        return HI_FAILURE;
    }

    if (PIXEL_FORMAT_RGB_1555 == enPixelFmt)
    {
        Surface.enColorFmt = OSD_COLOR_FMT_RGB1555;
    }
    else if (PIXEL_FORMAT_RGB_4444 == enPixelFmt)
    {
        Surface.enColorFmt = OSD_COLOR_FMT_RGB4444;
    }
    else if (PIXEL_FORMAT_RGB_8888 == enPixelFmt)
    {
        Surface.enColorFmt = OSD_COLOR_FMT_RGB8888;
    }
    else
    {
        printf("Pixel format is not support!\n");        
        return HI_FAILURE;
    }
	
    if(NULL == pstBitmap->pData)
    {
        printf("malloc osd memroy err!\n");        
        return HI_FAILURE;
    }
    CreateSurfaceByCanvas(filename, &Surface, (HI_U8*)(pstBitmap->pData), pstSize->u32Width, pstSize->u32Height, u32Stride);
	
    pstBitmap->u32Width  = Surface.u16Width;
    pstBitmap->u32Height = Surface.u16Height;
    
    if (PIXEL_FORMAT_RGB_1555 == enPixelFmt)
    {
        pstBitmap->enPixelFormat = PIXEL_FORMAT_RGB_1555;
    }
    else if (PIXEL_FORMAT_RGB_4444 == enPixelFmt)
    {
        pstBitmap->enPixelFormat = PIXEL_FORMAT_RGB_4444;
    }
    else if (PIXEL_FORMAT_RGB_8888 == enPixelFmt)
    {
        pstBitmap->enPixelFormat = PIXEL_FORMAT_RGB_8888;
    }

    int i,j;
    HI_U16 *pu16Temp;
    pu16Temp = (HI_U16*)pstBitmap->pData;
    
    if (bFil)
    {
        for (i=0; i<pstBitmap->u32Height; i++)
        {
            for (j=0; j<pstBitmap->u32Width; j++)
            {
                if (u16FilColor == *pu16Temp)
                {
                    *pu16Temp &= 0x0FFF;
                }

                pu16Temp++;
            }
        }

    }
        
    return HI_SUCCESS;
}




HI_S32 SAMPLE_RGN_Add(unsigned int Handle,int Type)
{
    	//printf("-------------------%s add rgn %d --------------------\n",__func__,Type);

	HI_S32 s32Ret = HI_SUCCESS;
	RGN_ATTR_S stRgnAttrSet;
	RGN_CANVAS_INFO_S stCanvasInfo;
	BITMAP_S stBitmap;
	SIZE_S stSize;
    printf("changwuyong 020\n");
	/* Photo logo */
	s32Ret = HI_MPI_RGN_GetAttr(Handle/*VencOsdHandle*/, &stRgnAttrSet);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_GetAttr failed! s32Ret: 0x%x.\n", s32Ret);
		return s32Ret;
	}
    printf("changwuyong 021\n");
	s32Ret = HI_MPI_RGN_GetCanvasInfo(Handle/*VencOsdHandle*/, &stCanvasInfo);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_GetCanvasInfo failed! s32Ret: 0x%x.\n", s32Ret);
		return s32Ret;
	}
    printf("changwuyong 022\n");
	stBitmap.pData   = (void*)stCanvasInfo.u32VirtAddr;
	stSize.u32Width  = stCanvasInfo.stSize.u32Width;
	stSize.u32Height = stCanvasInfo.stSize.u32Height;
	s32Ret = SAMPLE_RGN_UpdateCanvas("mm.bmp", &stBitmap, HI_FALSE, 0, &stSize, stCanvasInfo.u32Stride, stRgnAttrSet.unAttr.stOverlayEx.enPixelFmt);
    if (HI_SUCCESS != s32Ret)
	{
		printf("SAMPLE_RGN_UpdateCanvas failed! s32Ret: 0x%x.\n", s32Ret);
		return s32Ret;
	}
    printf("changwuyong 023\n");
	s32Ret = HI_MPI_RGN_UpdateCanvas(Handle/*VencOsdHandle*/);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_RGN_UpdateCanvas failed! s32Ret: 0x%x.\n", s32Ret);
		return s32Ret;
	}

	return HI_SUCCESS;
}

HI_S32 SAMPLE_RGN_CreateOverlayForVenc(HI_U32 u32ChnId, RGN_HANDLE Handle, HI_U32 u32X, HI_U32 u32Y, HI_U32 u32Width, HI_U32 u32Height)
{
	//printf("u32X  = %d u32Y = %d \n",u32X,u32Y);
	HI_S32 s32Ret = 0;
	MPP_CHN_S stChn;
	RGN_ATTR_S stRgnAttr;
	RGN_CHN_ATTR_S stChnAttr;

	/* Add cover to vpss group */
	stChn.enModId  = HI_ID_VENC;
	stChn.s32DevId = 0;
	stChn.s32ChnId = u32ChnId/*0*/;

	stRgnAttr.enType = OVERLAY_RGN;
	stRgnAttr.unAttr.stOverlay.enPixelFmt       = PIXEL_FORMAT_RGB_1555;
	stRgnAttr.unAttr.stOverlay.stSize.u32Width  = u32Width; //16x, value=bmp's Widthx3/2
	stRgnAttr.unAttr.stOverlay.stSize.u32Height = u32Height; //16x
	//stRgnAttr.unAttr.stOverlay.u32CanvasNum = 4; //Max:6
	stRgnAttr.unAttr.stOverlay.u32BgColor       = 0xffffffff/*0xffffffff*//*0x000003e0*/;

	s32Ret = HI_MPI_RGN_Create(Handle, &stRgnAttr);
	if (s32Ret != HI_SUCCESS)
	{
		printf("--@@_1 HI_MPI_RGN_Create failed! s32Ret: 0x%x.\n", s32Ret);
		return s32Ret;
	}

	stChnAttr.bShow  = HI_TRUE ;
	stChnAttr.enType = OVERLAY_RGN;
	stChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = u32X; //16x
	stChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = u32Y; //16x
	stChnAttr.unChnAttr.stOverlayChn.u32BgAlpha   = 0/*128*/; //Bg: transparent
	stChnAttr.unChnAttr.stOverlayChn.u32FgAlpha   = 128;
	stChnAttr.unChnAttr.stOverlayChn.u32Layer     = 4 /*7 Handle*/;

	// below para must keep
	stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bAbsQp 		= HI_FALSE ;
	stChnAttr.unChnAttr.stOverlayChn.stQpInfo.s32Qp  		= 0;
	stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bQpDisable 	= HI_FALSE ;

	stChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.u32Height = 48/*16 * (Handle % 2 + 1)*/;
	stChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.u32Width  = 48/*16 * (Handle % 2 + 1)*/;
	stChnAttr.unChnAttr.stOverlayChn.stInvertColor.u32LumThresh = 128;
	stChnAttr.unChnAttr.stOverlayChn.stInvertColor.enChgMod	= LESSTHAN_LUM_THRESH;
	stChnAttr.unChnAttr.stOverlayChn.stInvertColor.bInvColEn	= HI_FALSE ;


	s32Ret = HI_MPI_RGN_AttachToChn(Handle, &stChn, &stChnAttr);
	if (s32Ret != HI_SUCCESS)
	{
		printf("HI_MPI_RGN_AttachToChn failed! s32Ret: 0x%x.\n", s32Ret);
		return s32Ret;
	}

	return HI_SUCCESS;
}

HI_S32 SAMPLE_RGN_CreateVideoRegion(HI_VOID)
{
	HI_U32 u32ChnId 		= 0;
	RGN_HANDLE Handle 	= 0;
	HI_U32 coordinate_x 	= 0;
	HI_U32 coordinate_y 	= 0;
	HI_U32 region_with 	= 0;
	HI_U32 region_height = 0;

	u32ChnId 	= VENC_RECORD_CHNID;

	region_with		= 480;// 252 *3 / 2
	region_height 	= 320;// 28 * 3 / 2
	
	coordinate_x 	= 0;
	coordinate_y 	= 720 - 320;
	
	Handle 			= VENC_RECORD_LOGO_OSD_HANDLE;

    printf("changwuyong 010\n");
	SAMPLE_RGN_CreateOverlayForVenc(u32ChnId, Handle, coordinate_x, coordinate_y, region_with, region_height);
    printf("changwuyong 011\n");
	SAMPLE_RGN_Add( Handle, VENC_RECORD_LOGO_OSD_HANDLE);


	Handle 		= VENC_RECORD_TIME_OSD_HANDLE;

	//24bit��?bmp��???,��???��??����?3��??��?�ꨰ???��??��8bit
	region_with		= 544;  //18??��?��?14*32+4*16+16=528 ?�訢?16????????
	region_height 	= 24;  

	coordinate_x 	= 1280-16-260;//?��?YD��?���̡�??????
	coordinate_y 	= 720 - 24-12;//?????�訢?12????????
    printf("changwuyong 012\n");
	SAMPLE_RGN_CreateOverlayForVenc(u32ChnId, Handle, coordinate_x, coordinate_y, region_with, region_height);


	pthread_t osd_ThreadId = 0;
    printf("changwuyong 013\n");
	pthread_create(&osd_ThreadId, NULL, SAMPLE_RGN_AddVideoTimestamp, NULL);

	return HI_SUCCESS;
}


/******************************************************************************
* function :  H.264@1080p@30fps+H.264@VGA@30fps


******************************************************************************/
HI_S32 SAMPLE_VENC_1080P_CLASSIC(HI_VOID)
{
    PAYLOAD_TYPE_E enPayLoad[3]= {PT_H264, PT_H264,PT_H264};
    PIC_SIZE_E enSize[3] = {PIC_HD1080, PIC_VGA,PIC_QVGA};
	HI_U32 u32Profile = 0;
	
    VB_CONF_S stVbConf;
    SAMPLE_VI_CONFIG_S stViConfig = {0};
    
    VPSS_GRP VpssGrp;
    VPSS_CHN VpssChn;
    VPSS_GRP_ATTR_S stVpssGrpAttr;
    VPSS_CHN_ATTR_S stVpssChnAttr;
    VPSS_CHN_MODE_S stVpssChnMode;
    
    VENC_CHN VencChn;
    SAMPLE_RC_E enRcMode= SAMPLE_RC_CBR;
	
    HI_S32 s32ChnNum=0;
    
    HI_S32 s32Ret = HI_SUCCESS;
    HI_U32 u32BlkSize;
    SIZE_S stSize;
    char c;


    /******************************************
     step  1: init sys variable 
    ******************************************/
    memset(&stVbConf,0,sizeof(VB_CONF_S));
    
	SAMPLE_COMM_VI_GetSizeBySensor(&enSize[0]);
    if (PIC_HD1080 == enSize[0])
    {
        enSize[1] = PIC_VGA;
		s32ChnNum = 2;
    }
    else if (PIC_HD720 == enSize[0])
    {
        enSize[1] = PIC_VGA;			
		enSize[2] = PIC_QVGA;
		s32ChnNum = 1;
    }
    else
    {
        printf("not support this sensor\n");
        return HI_FAILURE;
    }
#ifdef hi3518ev201
	s32ChnNum = 1;
#endif
	printf("s32ChnNum = %d\n",s32ChnNum);

    stVbConf.u32MaxPoolCnt = 128;

    /*video buffer*/
	if(s32ChnNum >= 1)
    {
	    u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
	                enSize[0], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
	    stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
	    stVbConf.astCommPool[0].u32BlkCnt = g_u32BlkCnt;
	}
	if(s32ChnNum >= 2)
    {
	    u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
	                enSize[1], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
	    stVbConf.astCommPool[1].u32BlkSize = u32BlkSize;
	    stVbConf.astCommPool[1].u32BlkCnt =g_u32BlkCnt;
	}
	if(s32ChnNum >= 3)
    {
		u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
                enSize[2], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
		stVbConf.astCommPool[2].u32BlkSize = u32BlkSize;
		stVbConf.astCommPool[2].u32BlkCnt = g_u32BlkCnt;
    }

    /******************************************
     step 2: mpp system init. 
    ******************************************/
    s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("system init failed with %d!\n", s32Ret);
        goto END_VENC_1080P_CLASSIC_0;
    }

    SAMPLE_AUDIO_AiAenc();

    /******************************************
     step 3: start vi dev & chn to capture
    ******************************************/
    stViConfig.enViMode   = SENSOR_TYPE;
    stViConfig.enRotate   = ROTATE_NONE;
    stViConfig.enNorm     = VIDEO_ENCODING_MODE_AUTO;
    stViConfig.enViChnSet = VI_CHN_SET_NORMAL;
    stViConfig.enWDRMode  = WDR_MODE_NONE;
    s32Ret = SAMPLE_COMM_VI_StartVi(&stViConfig);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("start vi failed!\n");
        goto END_VENC_1080P_CLASSIC_1;
    }
    
    /******************************************
     step 4: start vpss and vi bind vpss
    ******************************************/
    s32Ret = SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[0], &stSize);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("SAMPLE_COMM_SYS_GetPicSize failed!\n");
        goto END_VENC_1080P_CLASSIC_1;
    }
	if(s32ChnNum >= 1)
	{
		VpssGrp = 0;
	    stVpssGrpAttr.u32MaxW = stSize.u32Width;
	    stVpssGrpAttr.u32MaxH = stSize.u32Height;
	    stVpssGrpAttr.bIeEn = HI_FALSE;
	    stVpssGrpAttr.bNrEn = HI_TRUE;
	    stVpssGrpAttr.bHistEn = HI_FALSE;
	    stVpssGrpAttr.bDciEn = HI_FALSE;
	    stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;
	    stVpssGrpAttr.enPixFmt = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
		
	    s32Ret = SAMPLE_COMM_VPSS_StartGroup(VpssGrp, &stVpssGrpAttr);
	    if (HI_SUCCESS != s32Ret)
	    {
	        SAMPLE_PRT("Start Vpss failed!\n");
	        goto END_VENC_1080P_CLASSIC_2;
	    }

	    s32Ret = SAMPLE_COMM_VI_BindVpss(stViConfig.enViMode);
	    if (HI_SUCCESS != s32Ret)
	    {
	        SAMPLE_PRT("Vi bind Vpss failed!\n");
	        goto END_VENC_1080P_CLASSIC_3;
	    }

		VpssChn = 0;
	    stVpssChnMode.enChnMode      = VPSS_CHN_MODE_USER;
	    stVpssChnMode.bDouble        = HI_FALSE;
	    stVpssChnMode.enPixelFormat  = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
	    stVpssChnMode.u32Width       = stSize.u32Width;
	    stVpssChnMode.u32Height      = stSize.u32Height;
	    stVpssChnMode.enCompressMode = COMPRESS_MODE_SEG;
	    memset(&stVpssChnAttr, 0, sizeof(stVpssChnAttr));
	    stVpssChnAttr.s32SrcFrameRate = -1;
	    stVpssChnAttr.s32DstFrameRate = -1;
	    s32Ret = SAMPLE_COMM_VPSS_EnableChn(VpssGrp, VpssChn, &stVpssChnAttr, &stVpssChnMode, HI_NULL);
	    if (HI_SUCCESS != s32Ret)
	    {
	        SAMPLE_PRT("Enable vpss chn failed!\n");
	        goto END_VENC_1080P_CLASSIC_4;
	    }
	}

    /******************************************
     step 5: start stream venc
    ******************************************/
    /*** HD1080P **/
    printf("\t c) cbr.\n");
    printf("\t v) vbr.\n");
    printf("\t f) fixQp\n");
    printf("please input choose rc mode!\n");
    /* c = (char)getchar(); */
    c = 'c';
    switch(c)
    {
        case 'c':
            enRcMode = SAMPLE_RC_CBR;
            break;
        case 'v':
            enRcMode = SAMPLE_RC_VBR;
            break;
        case 'f':
            enRcMode = SAMPLE_RC_FIXQP;
            break;
        default:
            printf("rc mode! is invaild!\n");
            goto END_VENC_1080P_CLASSIC_4;
    }

	/*** enSize[0] **/
	if(s32ChnNum >= 1)
	{
		VpssGrp = 0;
	    VpssChn = 0;
	    VencChn = 0;
	    s32Ret = SAMPLE_COMM_VENC_Start(VencChn, enPayLoad[0],\
	                                   gs_enNorm, enSize[0], enRcMode,u32Profile);
	    if (HI_SUCCESS != s32Ret)
	    {
	        SAMPLE_PRT("Start Venc failed!\n");
	        goto END_VENC_1080P_CLASSIC_5;
	    }

	    s32Ret = SAMPLE_COMM_VENC_BindVpss(VencChn, VpssGrp, VpssChn);
	    if (HI_SUCCESS != s32Ret)
	    {
	        SAMPLE_PRT("Start Venc failed!\n");
	        goto END_VENC_1080P_CLASSIC_5;
	    }
	}

    /******************************************
     step 6: stream venc process -- get stream, then save it to file. 
    ******************************************/
    s32Ret = SAMPLE_COMM_VENC_StartGetStream(s32ChnNum);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("Start Venc failed!\n");
        goto END_VENC_1080P_CLASSIC_5;
    }

    printf("please press twice ENTER to exit this sample\n");
    while(global_step_record != 2) {
            sleep(1);
            fflush(stdout);
    }
    global_step_record = 0;
    /* getchar(); */
    /* getchar(); */

    /******************************************
     step 7: exit process
    ******************************************/
    SAMPLE_COMM_VENC_StopGetStream();
    exit_audio_process();
END_VENC_1080P_CLASSIC_5:
	
    VpssGrp = 0;
	switch(s32ChnNum)
	{
		case 3:
			VpssChn = 2;   
		    VencChn = 2;
		    SAMPLE_COMM_VENC_UnBindVpss(VencChn, VpssGrp, VpssChn);
		    SAMPLE_COMM_VENC_Stop(VencChn);
		case 2:
			VpssChn = 1;   
		    VencChn = 1;
		    SAMPLE_COMM_VENC_UnBindVpss(VencChn, VpssGrp, VpssChn);
		    SAMPLE_COMM_VENC_Stop(VencChn);
		case 1:
			VpssChn = 0;  
		    VencChn = 0;
		    SAMPLE_COMM_VENC_UnBindVpss(VencChn, VpssGrp, VpssChn);
		    SAMPLE_COMM_VENC_Stop(VencChn);
			break;
			
	}
    SAMPLE_COMM_VI_UnBindVpss(stViConfig.enViMode);
	
END_VENC_1080P_CLASSIC_4:	//vpss stop

    VpssGrp = 0;
	switch(s32ChnNum)
	{
		case 3:
			VpssChn = 2;
			SAMPLE_COMM_VPSS_DisableChn(VpssGrp, VpssChn);
		case 2:
			VpssChn = 1;
			SAMPLE_COMM_VPSS_DisableChn(VpssGrp, VpssChn);
		case 1:
			VpssChn = 0;
			SAMPLE_COMM_VPSS_DisableChn(VpssGrp, VpssChn);
		break;
	
	}

END_VENC_1080P_CLASSIC_3:    //vpss stop       
    SAMPLE_COMM_VI_UnBindVpss(stViConfig.enViMode);
END_VENC_1080P_CLASSIC_2:    //vpss stop   
    SAMPLE_COMM_VPSS_StopGroup(VpssGrp);
END_VENC_1080P_CLASSIC_1:	//vi stop
    SAMPLE_COMM_VI_StopVi(&stViConfig);
END_VENC_1080P_CLASSIC_0:	//system exit
    SAMPLE_COMM_SYS_Exit();
    
    return s32Ret;    
}



HI_S32 SAMPLE_AUDIO_AiAenc(HI_VOID)
{
    HI_S32 i, s32Ret;
    AUDIO_DEV   AiDev = SAMPLE_AUDIO_AI_DEV;
    AI_CHN      AiChn;
    AUDIO_DEV   AoDev = SAMPLE_AUDIO_AO_DEV;
    AO_CHN      AoChn = 0;
    ADEC_CHN    AdChn = 0;
    HI_S32      s32AiChnCnt;
	HI_S32      s32AoChnCnt;
    HI_S32      s32AencChnCnt;
    AENC_CHN    AeChn;
    HI_BOOL     bSendAdec = HI_TRUE;
    FILE        *pfd = NULL;
    AIO_ATTR_S stAioAttr;

#ifdef HI_ACODEC_TYPE_TLV320AIC31
    stAioAttr.enSamplerate   = AUDIO_SAMPLE_RATE_8000;
    stAioAttr.enBitwidth     = AUDIO_BIT_WIDTH_16;
    stAioAttr.enWorkmode     = AIO_MODE_I2S_MASTER;
    stAioAttr.enSoundmode    = AUDIO_SOUND_MODE_MONO;
    stAioAttr.u32EXFlag      = 0;
    stAioAttr.u32FrmNum      = 30;
    stAioAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;
    stAioAttr.u32ChnCnt      = 1;
    stAioAttr.u32ClkSel      = 1;
#else
    stAioAttr.enSamplerate   = AUDIO_SAMPLE_RATE_8000;
    stAioAttr.enBitwidth     = AUDIO_BIT_WIDTH_16;
    stAioAttr.enWorkmode     = AIO_MODE_I2S_MASTER;
    stAioAttr.enSoundmode    = AUDIO_SOUND_MODE_MONO;
    stAioAttr.u32EXFlag      = 0;
    stAioAttr.u32FrmNum      = 30;
    stAioAttr.u32PtNumPerFrm = SAMPLE_AUDIO_PTNUMPERFRM;
    stAioAttr.u32ChnCnt      = 1;
    stAioAttr.u32ClkSel      = 0;
#endif
    gs_bAioReSample = HI_FALSE;
    enInSampleRate  = AUDIO_SAMPLE_RATE_BUTT;
    enOutSampleRate = AUDIO_SAMPLE_RATE_BUTT;
	u32AencPtNumPerFrm = stAioAttr.u32PtNumPerFrm;
		
    /********************************************
      step 1: config audio codec
    ********************************************/
    s32Ret = SAMPLE_COMM_AUDIO_CfgAcodec(&stAioAttr);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }

    /********************************************
      step 2: start Ai
    ********************************************/
    s32AiChnCnt = stAioAttr.u32ChnCnt; 
    s32Ret = SAMPLE_COMM_AUDIO_StartAi(AiDev, s32AiChnCnt, &stAioAttr, enOutSampleRate, gs_bAioReSample, NULL, 0);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }

    /********************************************
      step 3: start Aenc
    ********************************************/
    s32AencChnCnt = 1;
    s32Ret = SAMPLE_COMM_AUDIO_StartAenc(s32AencChnCnt, u32AencPtNumPerFrm, gs_enPayloadType);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_DBG(s32Ret);
        return HI_FAILURE;
    }

    /********************************************
      step 4: Aenc bind Ai Chn
    ********************************************/
    for (i=0; i<s32AencChnCnt; i++)
    {
        AeChn = i;
        AiChn = i;

        if (HI_TRUE == gs_bUserGetMode)
        {
            s32Ret = SAMPLE_COMM_AUDIO_CreatTrdAiAenc(AiDev, AiChn, AeChn);
            if (s32Ret != HI_SUCCESS)
            {
                SAMPLE_DBG(s32Ret);
                return HI_FAILURE;
            }
        }
        else
        {        
            s32Ret = SAMPLE_COMM_AUDIO_AencBindAi(AiDev, AiChn, AeChn);
            if (s32Ret != HI_SUCCESS)
            {
                SAMPLE_DBG(s32Ret);
                return s32Ret;
            }
        }
        printf("Ai(%d,%d) bind to AencChn:%d ok!\n",AiDev , AiChn, AeChn);
    }

    /********************************************
      step 5: start Adec & Ao. ( if you want )
    ********************************************/
    if (HI_TRUE == bSendAdec)
    {
        s32Ret = SAMPLE_COMM_AUDIO_StartAdec(AdChn, gs_enPayloadType);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }

		s32AoChnCnt = stAioAttr.u32ChnCnt;
        s32Ret = SAMPLE_COMM_AUDIO_StartAo(AoDev, s32AoChnCnt, &stAioAttr, enInSampleRate, gs_bAioReSample, NULL , 0);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }

        pfd = SAMPLE_AUDIO_OpenAencFile(AdChn, gs_enPayloadType);
        if (!pfd)
        {
            SAMPLE_DBG(HI_FAILURE);
            return HI_FAILURE;
        }        
        s32Ret = SAMPLE_COMM_AUDIO_CreatTrdAencAdec(AeChn, AdChn, pfd);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }

        s32Ret = SAMPLE_COMM_AUDIO_AoBindAdec(AoDev, AoChn, AdChn);
        if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_DBG(s32Ret);
            return HI_FAILURE;
        }

        printf("bind adec:%d to ao(%d,%d) ok \n", AdChn, AoDev, AoChn);
     }


    return HI_SUCCESS;

}



/******************************************************************************
* function    : main()
* Description : video venc sample
******************************************************************************/
int main(int argc, char *argv[])
{
    HI_S32 s32Ret;
    global_step_record = 0;
    pthread_t key_ThreadId = 0;
    unsigned long inputSample = 0;
    unsigned long maxOutputBytes = 0;

    ringmalloc(8000*10);
    pthread_create(&key_ThreadId, NULL, scan_key_main, NULL);
    signal(SIGINT, SAMPLE_VENC_HandleSig);
    signal(SIGTERM, SAMPLE_VENC_HandleSig);

    encoder = faacEncOpen(8000 , 1 , &inputSample, &maxOutputBytes);
    config = faacEncGetCurrentConfiguration(encoder);
    config->aacObjectType = MAIN;
    config->mpegVersion = MPEG4;
    //config->useLfe = 1;
    config->useTns = 1;
    config->allowMidside = 1;
    config->outputFormat = 0;  // RAW_STREAM = 0, ADTS_STREAM 1
    //config->bitRate = ;
    config->inputFormat = FAAC_INPUT_16BIT;
    faacEncSetConfiguration(encoder, config);

    printf("nInputSamples = %d nMaxOutputBytes = %d\n",inputSample,maxOutputBytes);
    s32Ret = SAMPLE_VENC_1080P_CLASSIC();
    
    if (HI_SUCCESS == s32Ret)
        printf("program exit normally!\n");
    else
        printf("program exit abnormally!\n");
    faacEncClose(encoder);
    ringfree();
    exit(s32Ret);
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
